package com.chenfan.mcn.component;

import com.chenfan.common.exception.BusinessException;
import com.chenfan.mcn.config.UserVoContextHolder;
import com.chenfan.mcn.enums.ApprovalEnum;
import com.chenfan.mcn.enums.FinanceChargeTypeEnum;
import com.chenfan.mcn.enums.IncomeContractTypeEnum;
import com.chenfan.mcn.enums.OperateLockEnum;
import com.chenfan.mcn.exception.McnErrorCode;
import com.chenfan.common.extension.lock.DistributedLockTemplate;
import com.chenfan.mcn.model.*;
import com.chenfan.mcn.model.rpc.BatchChargeClearCallback;
import com.chenfan.mcn.model.rpc.ChargeClearCallback;
import com.chenfan.mcn.service.*;
import com.chenfan.mcn.utils.BusinessAssert;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.stream.Collectors;

/**
 * 微服务装饰类
 *
 * @author wulg
 * @date 2022-03-21
 **/
@Component
public class MicroServiceFacade {

    @Autowired
    private IncomeContractService incomeContractService;

    @Autowired
    private StarRebateContractService starRebateContractService;

    @Autowired
    private StarMonthlySettlementService settlementService;

    @Autowired
    private LiveStarSettlementService liveStarSettlementService;

    @Autowired
    private ApprovalFlowService approvalFlowService;

    /**
     * 费用核销回调
     * @param callback
     * @return
     */
    public boolean clearPaybackCallback(ChargeClearCallback callback) {
        FinanceChargeTypeEnum chargeTypeEnum = FinanceChargeTypeEnum.getByType(callback.getChargeType());
        BusinessAssert.notNull(chargeTypeEnum, McnErrorCode.PARAM_ERROR, "非法费用类型");
        switch (chargeTypeEnum) {
            case MCN_INCOME_CHARGE:
            case LIVE_CONTRACT_CHARGE:
            case FORMAL_CONTRACT_CHARGE:
            case YES_FORMAL_CONTRACT_CHARGE:
            case NO_FORMAL_CONTRACT_CHARGE:
            case PIT_CHARGE:
            case ROI_SERVICE_CHARGE:
            case LIVE_ADVERTISING_CHARGE:
            case INCOME_CONTRACT_CHARGE:
            case FRAMEWORK_LIVE_CONTRACT_CHARGE:
            case OFFLINE_ADVERTISING_CHARGE:
            case ONLINE_YES_ADVERTISING_CHARGE:
            case ONLINE_NO_ADVERTISING_CHARGE:
            case NO_STAR_INCOME:
                //应收费用
                IncomeContract incomeContract = incomeContractService.getByCode(callback.getSourceBillCode(), UserVoContextHolder.getTenantId());
                BusinessAssert.notNull(incomeContract, McnErrorCode.INCOME_NOT_EXISTS);
                return DistributedLockTemplate.execute(OperateLockEnum.INCOME_CONTRACT.generateKey(incomeContract.getId()),
                        () -> incomeContractService.updatePayback(callback, incomeContract, false));
            case OFFLINE_COMMISSION_CHARGE:
                //线下佣金费
                IncomeContract liveContract = incomeContractService.getByCode(callback.getSourceBillCode(), UserVoContextHolder.getTenantId());
                BusinessAssert.notNull(liveContract, McnErrorCode.INCOME_NOT_EXISTS);
                BusinessAssert.notNull(IncomeContractTypeEnum.isLiveContract(liveContract.getContractType()), "非框架合同，不允许操作");
                return DistributedLockTemplate.execute(OperateLockEnum.INCOME_CONTRACT.generateKey(liveContract.getId()),
                        () -> incomeContractService.updatePayback(callback, liveContract, true));
            case OTHER_INCOME:
                //红人返点
                StarRebateContract starRebateContract = starRebateContractService.getByCode(callback.getSourceBillCode(), UserVoContextHolder.getTenantId());
                BusinessAssert.notNull(starRebateContract, McnErrorCode.DATA_NOT_FOUND, "红人返点合同不存在");
                return DistributedLockTemplate.execute(OperateLockEnum.STAR_REBATE_CONTRACT.generateKey(starRebateContract.getId()),
                        () -> starRebateContractService.updatePayback(callback, starRebateContract.getId()));

            case STAR_MONTHLY_SETTLEMENT_CHARGE:
                //红人月度结算单
                StarMonthlySettlementSub subSettlement = settlementService.getSubSettlementByCode(callback.getSourceBillCode(), true);
                return DistributedLockTemplate.execute(OperateLockEnum.STAR_MONTHLY_SETTLEMENT.generateKey(subSettlement.getSettlementId()),
                        () -> settlementService.updatePayback(callback, subSettlement));

            case LIVE_STAR_SETTLEMENT_CHARGE:
                //直播红人结算单
                LiveStarSettlement liveStarSettlement = liveStarSettlementService.getSettlementByCode(callback.getSourceBillCode(), true);
                return DistributedLockTemplate.execute(OperateLockEnum.LIVE_CONTRACT_COMMODITY.generateKey(liveStarSettlement.getId()),
                        () -> liveStarSettlementService.updatePayback(callback, liveStarSettlement.getId()));
            default:
                throw new BusinessException(McnErrorCode.BUSINESS_ERROR.code(), "暂不支持该费用类型："+chargeTypeEnum.getDesc());
        }
    }

    /**
     * 批量费用核销回调
     * @param callback
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean batchClearPaybackCallback(BatchChargeClearCallback callback) {
        callback.getBody().stream().map(e -> {
            ChargeClearCallback item = new ChargeClearCallback();
            BeanUtils.copyProperties(e, item);
            item.setOperateDate(callback.getOperateDate());
            item.setOperatorId(callback.getOperatorId());
            item.setOperatorName(callback.getOperatorName());
            item.setTenantId(callback.getTenantId());
            return item;
        }).collect(Collectors.toList()).forEach(e -> {
            this.clearPaybackCallback(e);
        });
        return true;
    }

    /**
     * 根据来源单号获取直播红人结算单最新流程ID
     * @param sourceBillCode
     * @return
     */
    public Long getNewFlowIdOfLiveStarSettlement(String sourceBillCode) {
        LiveStarSettlement liveStarSettlement = liveStarSettlementService.getSettlementByCode(sourceBillCode, true);
        return approvalFlowService.getFlowId(liveStarSettlement.getId(), ApprovalEnum.LIVE_STAR_SETTLEMENT.getProcessId());
    }
}
